/*
 * Copyright (C) 2011-2015 ShenZhen iBOXPAY Information Technology Co.,Ltd.
 * 
 * All right reserved.
 * 
 * This software is the confidential and proprietary
 * information of iBoxPay Company of China. 
 * ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only
 * in accordance with the terms of the contract agreement 
 * you entered into with iBoxpay inc.
 *
 */

package com.iboxpay.sdk;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

/**
 * The class SignUtil.
 *
 * Description: 
 *
 * @author: nieminjie
 * @since: 2016年2月29日	
 * @version: $Revision$ $Date$ $LastChangedBy$
 *
 */

public class SignUtil {

	/**
	 * 签名
	 * @param signMap
	 * 					待签名Map
	 * 
	 * @param signType
	 * 					签名类型
	 * 
	 * @param publicKey
	 * 					公钥
	 * 
	 * @param privateKey
	 * 					私钥
	 * 
	 * @return
	 */
	public static String sign(Map<String, ?> signMap, String signType, String publicKey, String privateKey) {
		PubPriKey key = new PubPriKey();
		key.setPrivateKey(privateKey);
		key.setPublicKey(publicKey);
		return sign(signMap, signType, key);
	}

	/**
	 * 签名
	 * @param signMap
	 * 					待签名Map
	 * 
	 * @param signType
	 * 					签名类型
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @return
	 */
	public static String sign(Map<String, ?> signMap, String signType, PubPriKey key) {
		String sign = "";
		if (null == signMap || signMap.isEmpty() || null == key) {
			return sign;
		}

		// 获取待签名的字符串
		String toSign = "";

		// MD5加密
		if (SignType.MD5.equals(signType)) {
			toSign = getToSign(signMap, key.getPrivateKey());
			sign = MD5.encode2MD5(toSign.toString());
		} else if (SignType.RSA.equals(signType)) {
//			try {
//				toSign = getToSign(signMap, "");
//
//				// 签名默认私钥加密
//				sign = new String(RSACoder.encryptByPrivateKey(toSign.toString().getBytes(), key.getPrivateKey()), "UTF-8");
//			} catch (UnsupportedEncodingException e) {
//				e.printStackTrace();
//			}
		} else {
//			toSign = getToSign(signMap, "");
//
//			// 随机RSA签名默认公钥加密随机数
//			sign = RandomSignUtil.encryptWithRSA(toSign, key.getPublicKey(), true);
		}

		return sign;
	}

	/**
	 * 验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param signType
	 * 					签名类型
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * @return
	 */
	public static boolean verifySign(Map<String, ?> signMap, String signType, String sign, String publicKey, String privateKey) {
		PubPriKey key = new PubPriKey();
		key.setPrivateKey(privateKey);
		key.setPublicKey(publicKey);
		return verifySign(signMap, signType, sign, key);
	}

	/**
	 * 验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param signType
	 * 					签名类型
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * @return
	 */
	public static boolean verifySign(Map<String, ?> signMap, String signType, String sign, PubPriKey key) {
		boolean result = false;
		if (null == signMap || signMap.isEmpty() || null == key) {
			return result;
		}

		// MD5加密
		if (SignType.MD5.equals(signType)) {
			result = verifyMD5Sign(signMap, sign, key.getPrivateKey());
		} else if (SignType.RSA.equals(signType)) {
			result = verifyRSASign(signMap, sign, key);
		} else {
			result = verifyRandomRSASign(signMap, sign, key);
		}

		return result;
	}

	/**
	 * MD5验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param key
	 * 					密钥
	 * 
	 * @return
	 */
	public static boolean verifyMD5Sign(Map<String, ?> signMap, String sign, String key) {
		boolean result = false;

		// 签名
		String newSign = sign(signMap, SignType.MD5, "", key);
		if (String.valueOf(sign).equalsIgnoreCase(String.valueOf(newSign))) {
			result = true;
		}
		return result;
	}

	/**
	 * RSA公钥验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param publicKey
	 * 					公钥
	 * 
	 * @return
	 */
	public static boolean verifyRSASign(Map<String, ?> signMap, String sign, String publicKey) {
		return verifyRSASign(signMap, sign, publicKey, true);
	}

	/**
	 * RSA公钥验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @return
	 */
	public static boolean verifyRSASign(Map<String, ?> signMap, String sign, PubPriKey key) {
		return verifyRSASign(signMap, sign, key, true);
	}

	/**
	 * RSA验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param key
	 * 					密钥
	 * 
	 * @return
	 */
	public static boolean verifyRSASign(Map<String, ?> signMap, String sign, String key, boolean isPublic) {
		PubPriKey keyObj = new PubPriKey();
		if (isPublic) {
			keyObj.setPublicKey(key);
		} else {
			keyObj.setPrivateKey(key);
		}
		return verifyRSASign(signMap, sign, keyObj, isPublic);
	}

	/**
	 * RSA公钥验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @return
	 */
	public static boolean verifyRSASign(Map<String, ?> signMap, String sign, PubPriKey key, boolean isPublic) {
		boolean result = false;

		if (StringUtils.isNotBlank(sign) && null != key) {

			// 使用公钥签名
			String toSign = getToSign(signMap, "");

			// 使用解密
			String orgToSign = "";
			try {
				if (isPublic) {
					orgToSign = new String(RSACoder.decryptByPublicKey(sign.getBytes(), key.getPublicKey()), "UTF-8");
				} else {
					orgToSign = new String(RSACoder.decryptByPrivateKey(sign.getBytes(), key.getPrivateKey()), "UTF-8");
				}
				orgToSign = new String(RSACoder.decryptByPublicKey(sign.getBytes(), key.getPublicKey()), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			if (String.valueOf(toSign).equalsIgnoreCase(String.valueOf(orgToSign))) {
				result = true;
			}
		}
		return result;
	}

	/**
	 * RandomRSA验签（默认私钥解密）
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param privateKey
	 * 					私钥，用于解密
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @return
	 */
	public static boolean verifyRandomRSASign(Map<String, ?> signMap, String sign, String privateKey) {
		return verifyRandomRSASign(signMap, sign, privateKey, false);
	}

	/**
	 * RandomRSA私钥验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @return
	 */
	public static boolean verifyRandomRSASign(Map<String, ?> signMap, String sign, PubPriKey key) {
		return verifyRandomRSASign(signMap, sign, key, false);
	}

	/**
	 * RandomRSA验签（默认私钥解密）
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param privateKey
	 * 					私钥，用于解密
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @return
	 */
	public static boolean verifyRandomRSASign(Map<String, ?> signMap, String sign, String key, boolean isPublic) {
		PubPriKey keyObj = new PubPriKey();
		if (isPublic) {
			keyObj.setPublicKey(key);
		} else {
			keyObj.setPrivateKey(key);
		}
		return verifyRandomRSASign(signMap, sign, keyObj, isPublic);
	}

	/**
	 * RandomRSA验签
	 * @param signMap
	 * 					待签名字符串Map
	 * 
	 * @param key
	 * 					公私钥对象
	 * 
	 * @param sign
	 * 					比较签名字符串
	 * 
	 * @param isPublic
	 * 					是否公钥
	 * 
	 * @return
	 */
	public static boolean verifyRandomRSASign(Map<String, ?> signMap, String sign, PubPriKey key, boolean isPublic) {
		boolean result = false;

		if (StringUtils.isNotBlank(sign) && null != key) {

			// 使用公钥签名
			String toSign = getToSign(signMap, "");

			// 解密
			String orgToSign = RandomSignUtil.getDecryptReqContentWithRsa3Des(sign, key, !isPublic);

			if (String.valueOf(toSign).equalsIgnoreCase(String.valueOf(orgToSign))) {
				result = true;
			}
		}
		return result;
	}

	/**
	 * 获取待签名的字符串
	 * @param signMap
	 * @param key
	 * @return
	 */
	private static String getToSign(Map<String, ?> signMap, String key) {
		if (null == key) {
			key = "";
		}

		// 需签名的字符串
		StringBuilder toSign = new StringBuilder();
		if (null != signMap && !signMap.isEmpty()) {
			Map toAppendMap = new HashMap(signMap);
			toAppendMap.remove("sign");
			toAppendMap.remove("signType");
			toSign.append(MapUtil.sortAppend(toAppendMap));
		}

		// 最后加上密钥
		toSign.append(key);
		return toSign.toString();
	}
}
